#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h> 
#include <linux/irq.h>
#include <linux/platform_device.h> 
#include <linux/miscdevice.h>
#include <linux/input.h>

#define KEYINPUT_CNT 	1 				/* 设备号个数 */ 
#define KEYINPUT_NAME 	"keyinput" 		/* 名字 */ 
#define KEYVALUE 		0X01 			/* KEY0按键值 */ 
#define INVAKEY 		0XFF 			/* 无效的按键值 */ 
#define KEY_NUM 		2 				/* 按键数量 */

struct keydesc_st
{
	unsigned char value;
	unsigned char privalue;
	int gpio;
	int irqnum;
	char name[10];
	irqreturn_t (*handler)(int, void *);
};

struct keyio_st
{
	unsigned char curkeynum;
	struct device_node *node;
	struct timer_list timer;	
	struct input_dev *inputdev;
	struct keydesc_st key[KEY_NUM];
};
static struct keyio_st keydev;

static irqreturn_t key0_handler(int irqnum, void *ptr)
{
	keydev.curkeynum =0;
	mod_timer(&keydev.timer, jiffies+msecs_to_jiffies(10));

	return IRQ_RETVAL(IRQ_HANDLED);
}

static irqreturn_t key1_handler(int irqnum, void *ptr)
{
	keydev.curkeynum =1;
	mod_timer(&keydev.timer, jiffies+msecs_to_jiffies(10));

	return IRQ_RETVAL(IRQ_HANDLED);
}

static void timer_func(struct timer_list *timer)
{
	unsigned char value,currentValue;

	value = keydev.key[keydev.curkeynum].privalue;
	currentValue = gpio_get_value(keydev.key[keydev.curkeynum].gpio);
	
	if(value ==1 && currentValue==0)
	{
		input_report_key(keydev.inputdev,keydev.key[keydev.curkeynum].value,1);
		input_sync(keydev.inputdev);
	}
	else if(value==0 && currentValue==1)
	{
		input_report_key(keydev.inputdev,keydev.key[keydev.curkeynum].value,0);
		input_sync(keydev.inputdev);
	}

	keydev.key[keydev.curkeynum].privalue = currentValue;
}

static int keyio_init(void)
{
	int ret =0;
	int i=0;

	keydev.node = of_find_node_by_path("/my-keys");
	if(keydev.node ==NULL)
	{
		printk("of_find_node_by_path error\r\n");
		return -EINVAL;
	}

	for(i=0;i<KEY_NUM;i++)
	{
		keydev.key[i].gpio = of_get_named_gpio(keydev.node, "gpios", i);
		if(keydev.key[i].gpio <0)
		{
			printk("of_get_named_gpio error\r\n");
			return -EINVAL;
		}

		memset(keydev.key[i].name, 0,sizeof(keydev.key[i].name));
		sprintf(keydev.key[i].name,"key%d",i);

		ret = gpio_request(keydev.key[i].gpio, keydev.key[i].name);
		if(ret <0)
		{
			printk("gpio_request\r\n");
			return -EINVAL;
		}

		ret = gpio_direction_input(keydev.key[i].gpio);
		if(ret <0)
		{
			printk("gpio_direction_input\r\n");
			return -EINVAL;
		}

		keydev.key[i].irqnum = irq_of_parse_and_map(keydev.node, i);
		if(keydev.key[i].irqnum <0)
		{
			printk("irq_of_parse_and_map\r\n");
			return -EINVAL;
		}

		keydev.key[0].handler = key0_handler;
		keydev.key[1].handler = key1_handler;
		keydev.key[0].value = KEY_0;
		keydev.key[1].value = KEY_9;
		keydev.key[i].privalue = KEYVALUE;

		ret = request_irq(keydev.key[i].irqnum, keydev.key[i].handler, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, keydev.key[i].name, NULL);
		if(ret <0)
		{
			printk("request_irq\r\n");
			return -EINVAL;
		}
	}

	//设置定时器
	timer_setup(&keydev.timer,&timer_func,0);

	//创建输入设备
	keydev.inputdev = input_allocate_device();
	if(keydev.inputdev ==NULL)
	{
		printk("input_allocate_device\r\n");
		return -EINVAL;
	}
	keydev.inputdev->name = KEYINPUT_NAME;
	
	//设置按键事件
	__set_bit(EV_KEY,keydev.inputdev->evbit);
	__set_bit(EV_REP,keydev.inputdev->evbit);
	__set_bit(KEY_0,keydev.inputdev->keybit);
	__set_bit(KEY_9,keydev.inputdev->keybit);

	//注册输入设备
	ret = input_register_device(keydev.inputdev);
	if(ret)
	{
		printk("input_register_device\r\n");
		return -EINVAL;
	}

	return 0;
}

static int __init keyinput_init(void)
{
	int ret =0;

	ret = keyio_init();
	if(ret <0)
	{
		printk("keyio_init error\r\n");
		return -EINVAL;
	}

	printk("keyinput_init sucess\r\n");
	return 0;
}

static void __exit keyinput_exit(void)
{
	int i=0;

	for(i=0;i<KEY_NUM;i++)
	{
		free_irq(keydev.key[i].irqnum, NULL);
		gpio_free(keydev.key[i].gpio);
	}

	del_timer_sync(&keydev.timer);

	input_unregister_device(keydev.inputdev);
	input_free_device(keydev.inputdev);

	printk("keyinput_exit sucess\r\n");
}

module_init(keyinput_init);
module_exit(keyinput_exit);
MODULE_AUTHOR("jtb");
MODULE_LICENSE("GPL");

